package com.chentongwei.security.validate.authentication.mobile;

import com.chentongwei.security.validate.enums.DefaultLoginProcessingUrlEnum;
import com.chentongwei.security.validate.enums.ValidateCodeParamNameEnum;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * @author chentongwei@bshf360.com 2018-03-28 10:18
 */
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

  // ~ Static fields/initializers
  // =====================================================================================

  public static final String MOBILE_PARAMETER = ValidateCodeParamNameEnum.DEFAULT_PARAMETER_NAME_MOBILE.value();

  private boolean postOnly = true;

  // ~ Constructors
  // ===================================================================================================

  public SmsCodeAuthenticationFilter() {
    super(new AntPathRequestMatcher(DefaultLoginProcessingUrlEnum.MOBILE.url(), "POST"));
  }

  // ~ Methods
  // ========================================================================================================
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request,
                                              HttpServletResponse response) throws AuthenticationException {
    if (postOnly && !Objects.equals(request.getMethod(), "POST")) {
      throw new AuthenticationServiceException(
          "Authentication method not supported: " + request.getMethod());
    }

    String mobile = obtainMobile(request);

    if (mobile == null) {
      mobile = "";
    }
    mobile = mobile.trim();

    SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);

    return this.getAuthenticationManager().authenticate(authRequest);
  }

  /**
   * Enables subclasses to override the composition of the username, such as by
   * including additional values and a separator.
   *
   * @param request so that request attributes can be retrieved
   * @return the username that will be presented in the <code>Authentication</code>
   * request token to the <code>AuthenticationManager</code>
   */
  protected String obtainMobile(HttpServletRequest request) {
    return request.getParameter(MOBILE_PARAMETER);
  }

  /**
   * Provided so that subclasses may configure what is put into the authentication
   * request's details property.
   *
   * @param request     that an authentication request is being created for
   * @param authRequest the authentication request object that should have its details
   *                    set
   */
  protected void setDetails(HttpServletRequest request,
                            SmsCodeAuthenticationToken authRequest) {
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
  }
}
